﻿#region

using System;
using System.Windows;

#endregion

namespace Radovici.SharedLibrary
{
    /// <summary>
    /// Authored by Robby Ingebretsen at http://nerdplusart.com.
    /// <remarks>Both Vector.cs and AnimatingPanelBase.cs</remarks>
    /// </summary>
    public struct Vector
    {
        internal double _x;
        internal double _y;

        public Vector(double x, double y)
        {
            _x = x;
            _y = y;
        }

        public double X
        {
            get { return _x; }
            set { _x = value; }
        }

        public double Y
        {
            get { return _y; }
            set { _y = value; }
        }

        public double Length
        {
            get { return Math.Sqrt((X*X) + (Y*Y)); }
        }

        public double LengthSquared
        {
            get { return ((X*X) + (Y*Y)); }
        }

        public static bool operator ==(Vector vector1, Vector vector2)
        {
            return ((vector1.X == vector2.X) && (vector1.Y == vector2.Y));
        }

        public static bool operator !=(Vector vector1, Vector vector2)
        {
            return !(vector1 == vector2);
        }

        public static bool Equals(Vector vector1, Vector vector2)
        {
            return (vector1.X.Equals(vector2.X) && vector1.Y.Equals(vector2.Y));
        }

        public override bool Equals(object o)
        {
            if ((o == null) || !(o is Vector))
            {
                return false;
            }
            var vector = (Vector) o;
            return Equals(this, vector);
        }

        public bool Equals(Vector value)
        {
            return Equals(this, value);
        }

        public override int GetHashCode()
        {
            return (X.GetHashCode() ^ Y.GetHashCode());
        }

        public void Normalize()
        {
            this = (this/Math.Max(Math.Abs(X), Math.Abs(Y)));
            this = (this/Length);
        }

        public static double CrossProduct(Vector vector1, Vector vector2)
        {
            return ((vector1.X*vector2.Y) - (vector1.Y*vector2.X));
        }

        public static double AngleBetween(Vector vector1, Vector vector2)
        {
            double y = (vector1.X*vector2.Y) - (vector2.X*vector1.Y);
            double x = (vector1.X*vector2.X) + (vector1.Y*vector2.Y);
            return (Math.Atan2(y, x)*57.295779513082323);
        }

        public static Vector operator -(Vector vector)
        {
            return new Vector(-vector.X, -vector.Y);
        }

        public void Negate()
        {
            X = -X;
            Y = -Y;
        }

        public static Vector operator +(Vector vector1, Vector vector2)
        {
            return new Vector(vector1.X + vector2.X, vector1.Y + vector2.Y);
        }

        public static Vector Add(Vector vector1, Vector vector2)
        {
            return new Vector(vector1.X + vector2.X, vector1.Y + vector2.Y);
        }

        public static Vector operator -(Vector vector1, Vector vector2)
        {
            return new Vector(vector1.X - vector2.X, vector1.Y - vector2.Y);
        }

        public static Vector Subtract(Vector vector1, Vector vector2)
        {
            return new Vector(vector1.X - vector2.X, vector1.Y - vector2.Y);
        }

        public static Point operator +(Vector vector, Point point)
        {
            return new Point(point.X + vector.X, point.Y + vector.Y);
        }

        public static Point Add(Vector vector, Point point)
        {
            return new Point(point.X + vector.X, point.Y + vector.Y);
        }

        public static Vector operator *(Vector vector, double scalar)
        {
            return new Vector(vector.X*scalar, vector.Y*scalar);
        }

        public static Vector Multiply(Vector vector, double scalar)
        {
            return new Vector(vector.X*scalar, vector.Y*scalar);
        }

        public static Vector operator *(double scalar, Vector vector)
        {
            return new Vector(vector.X*scalar, vector.Y*scalar);
        }

        public static Vector Multiply(double scalar, Vector vector)
        {
            return new Vector(vector.X*scalar, vector.Y*scalar);
        }

        public static Vector operator /(Vector vector, double scalar)
        {
            return (vector*(1.0/scalar));
        }

        public static Vector Divide(Vector vector, double scalar)
        {
            return (vector*(1.0/scalar));
        }

        public static double operator *(Vector vector1, Vector vector2)
        {
            return ((vector1.X*vector2.X) + (vector1.Y*vector2.Y));
        }

        public static double Multiply(Vector vector1, Vector vector2)
        {
            return ((vector1.X*vector2.X) + (vector1.Y*vector2.Y));
        }

        public static double Determinant(Vector vector1, Vector vector2)
        {
            return ((vector1.X*vector2.Y) - (vector1.Y*vector2.X));
        }

        public static explicit operator Size(Vector vector)
        {
            return new Size(Math.Abs(vector.X), Math.Abs(vector.Y));
        }

        public static explicit operator Point(Vector vector)
        {
            return new Point(vector.X, vector.Y);
        }
    }
}